package com.majun.config.filter2;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 记录请求日志
 */
public class StandardRequestLogFilter extends HttpFilter {

    private final Logger log = LoggerFactory.getLogger(StandardRequestLogFilter.class);
    private static final long serialVersionUID = 8991118181953196532L;


    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        // Wrapper 封装 Request 和 Response
        ContentCachingRequestWrapper cachingRequest = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper cachingResponse = new ContentCachingResponseWrapper(response);

        // 继续执行请求链 这里必须放在前面,不然不会调用
        chain.doFilter(cachingRequest, cachingResponse);

        /**
         * 在请求完成后记录请求、响应日志
         */
        // 请求方法
        String method = request.getMethod();

        //请求的URL
        String url = request.getRequestURL().toString();

//        BufferedReader reader = cachingRequest.getReader();
//        String requestBody1 = getRequestBody(cachingRequest);
//        System.err.println(requestBody1);
        // 请求体
        byte[] requestContent = cachingRequest.getContentAsByteArray();

        String body = new String(requestContent);
        if (StringUtils.isNotEmpty(body)) {
            body = body.replaceAll("\n", "");
        }

        final String params = getRequestParams(request);

        final String ip = getRequestIp(request);

        log.info("HttpRequest ===>>> method:[{}] url:[{}] params:[{}] body:[{}] ip:[{}] ", method, url, params, body, ip);

        // 继续执行请求链
//        chain.doFilter(cachingRequest, cachingResponse);

        // 响应状态
        int status = response.getStatus();
        // 响应体
        byte[] responseContent = cachingResponse.getContentAsByteArray();
        String data = new String(responseContent);

//        log.info("HttpResponse <<<=== status:[{}]", status);
        log.info("HttpResponse <<<=== status:[{}] data:[{}]", status, data);

        //把缓存的响应数据，响应给客户端
        // 这一步很重要，把缓存的响应内容，输出到客户端
        cachingResponse.copyBodyToResponse();
    }

    private String getRequestBody(HttpServletRequest request) {
        int contentLength = request.getContentLength();
        if (contentLength <= 0) {
            return "";
        }
        try {
            return IOUtils.toString(request.getReader());
        } catch (IOException e) {
            log.error("获取请求体失败", e);
            return "";
        }
    }

    private String getRequestParams(final HttpServletRequest request) {
        Map<String, String[]> requestParams = request.getParameterMap();
        final List<String> pairs = new ArrayList<>(10);
        if (MapUtils.isNotEmpty(requestParams)) {
            for (final Map.Entry<String, String[]> entry : requestParams.entrySet()) {
                final String name = entry.getKey();
                final String[] value = entry.getValue();
                if (value == null) {
                    pairs.add(name + "=");
                } else {
                    for (final String v : value) {
                        pairs.add(name + "=" + StringUtils.trimToEmpty(v));
                    }
                }
            }
        }
        String requestParamsStr = CollectionUtils.isEmpty(pairs) ? StringUtils.EMPTY : String.join("&", pairs);
        if (StringUtils.equalsIgnoreCase(request.getContentType(), MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
            try {
                requestParamsStr = URLDecoder.decode(requestParamsStr, StandardCharsets.UTF_8.name());
            } catch (UnsupportedEncodingException ignored) {
            }
        }
        return requestParamsStr;
    }

    private String getRequestIp(final HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
            // 这是一个可以伪造的头
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        }
        // 最后一个为RemoteAddr
        int pos = ip.lastIndexOf(',');
        if (pos >= 0) {
            ip = ip.substring(pos);
        }
        if ("0:0:0:0:0:0:0:1".equals(ip)) {
            ip = "127.0.0.1";
        }
        return ip;
    }
}